package com.lp.mgt.controllers;

import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.lp.mgt.commons.CustomResult;
import com.lp.mgt.entities.Menu;
import com.lp.mgt.entities.Role;
import com.lp.mgt.entities.User;
import com.lp.mgt.services.LoginService;
import com.lp.mgt.services.MenuService;
import com.lp.mgt.services.UserService;
import com.lp.mgt.utils.PicCodeUtil;
import com.lp.mgt.utils.TreeUtils;
import com.lp.mgt.weather.WeatherDataService;
import com.lp.mgt.weather.WeatherResponse;



@Controller
public class LoginCtr {
	private Logger logger = LoggerFactory.getLogger(LoginCtr.class);
	    @Autowired
	    private LoginService loginService;
	    @Autowired
	    private UserService userService;
	    @Autowired
	    private MenuService menuService;
	    @Autowired
	    private WeatherDataService weatherDataService;
		@Autowired
		private RestTemplate restTemplate;
		@Autowired
		private StringRedisTemplate stringRedisTemplate;
		
	    //初始跳登录页
		@RequestMapping("/loginPage")
		public String toLoginPage() {
			logger.info("进入登录页面(loginPage)");
			return "loginPage.html";
		}
		//登录成功跳主页
		@RequestMapping("/mainPage")
		@RequiresPermissions("index")
		public String toMainPage(Model model) {
			//获取当前登录用户
			User currentUser=(User) SecurityUtils.getSubject().getPrincipal();
			model.addAttribute("currentUser", currentUser);//当前用户
			//获取当前用户的菜单权限:
			//本来可以直接取当前用户角色中对应的菜单，但是一个热可能有多个角色不好取值，并且菜单排序也会存在问题
			List<Role> roles=currentUser.getRoles();//取用户所有角色
			//jdk1.8 新增的集合Stream API贼好用。
			List<Menu> menus=roles.stream()
					.map(Role::getMenus)//每个角色返回Stream<List<Menu>>，而不是Stream<Menu>
					.flatMap(List::stream)//合并成Stream<Menu>
					.distinct()//去重：需要重写对象的equals和hashCode方法
					.filter((Menu menu) -> !"F".equals(menu.getMenuType()))//过滤：除按钮外的资源菜单
					.collect(Collectors.toList());//流转列表
			//jdk1.8集合多字段排序lambda表达式:先按parentId升序，再按orderNum升序
			menus.sort(Comparator.comparing(Menu::getParentId).thenComparing(Menu::getOrderNum));
			//前端并没有根据shiro和thymeleaf标签shiro:hasPermission来判断显示或隐藏（可能因为用的循环）
			menus.forEach((m) -> System.out.println("拥有菜单权限："+m.getMenuName()));
			model.addAttribute("menus", TreeUtils.getChildPerms(menus,"i","parentId","menuId","setChildren"));//父节点传i，不查首页
			//查询天气情况，前端动画判断
/*			WeatherResponse weather=weatherDataService.getDataByCityName("成都");
			if("1000".equals(weather.getStatus())){
				String type=weather.getData().getForecast().get(0).getType();
				String weatherType=null;
				if (type.indexOf("晴")!=-1) {
					weatherType="QING";
				}else if(type.indexOf("云")!=-1 || type.indexOf("阴")!=-1) {
					weatherType="YIN";
				}else if(type.indexOf("雨")!=-1) {
					weatherType="YU";
				}else if(type.indexOf("雪")!=-1) {
					weatherType="XUE";
				}
				logger.info("天气类型："+weatherType);
				model.addAttribute("type",weatherType);
			}else {
				model.addAttribute("msg","天气查询失败");
			}*/
			logger.info("进入主页面(mainPage)");
			return "mainPage.html";
		}
		//登出跳登录页
	    @RequestMapping("/logout")
	    public String logOut(HttpSession session) {
	    	logger.info("注销");
	        loginService.logout();
	        return "loginPage.html";
	    }
	    //没权限友好页面
	    @RequestMapping("/403")
	    public String unauthorizedRole(){
	        System.out.println("------没有权限-------");
	        return "/error/403.html";
	    }
	    
		@RequestMapping("/getPicCode")
		public void createCode(HttpServletRequest req, HttpServletResponse resp){
			// 调用工具类生成的验证码和验证码图片
	        Map<String, Object> codeMap = PicCodeUtil.generateCodeAndPic();
	        // 将四位数字的验证码保存到Session中。
	        HttpSession session = req.getSession();
	        session.setAttribute("picCode", codeMap.get("code").toString());
	        // 禁止图像缓存。
	        resp.setHeader("Pragma", "no-cache");
	        resp.setHeader("Cache-Control", "no-cache");
	        resp.setDateHeader("Expires", -1);
	        resp.setContentType("image/jpeg");
	        // 将图像输出到Servlet输出流中。
	        ServletOutputStream sos;
	        try {
	            sos = resp.getOutputStream();
	            ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos);
	            sos.close();
	        } catch (IOException e) {
	            e.printStackTrace();
	        }
		}	  
		
	    //登录请求
	    @RequestMapping(value = "/login", method = RequestMethod.POST)
	    public String submitLogin(User user,RedirectAttributes model,HttpServletRequest request) {	    	
	    	// 验证session验证码
	        String sessionCode = request.getSession().getAttribute("picCode").toString();
	    	if (!user.getPicCode().equalsIgnoreCase(sessionCode)){
	    		logger.info("验证码输入有误");
	    		model.addAttribute("msg","验证码输入有误");
	    		return "redirect:/loginPage";
	    	}
	    	Boolean flag;
	    	try {
	    		flag=loginService.login(user);
	    	}catch (Exception e) {
				logger.debug("发生异常");
				model.addAttribute("msg","登录异常，请重试");
				return "redirect:/loginPage";
			}
	        logger.info("是否验证成功："+String.valueOf(flag));
	        if(flag) {
	        	return "redirect:/mainPage";
	        }else {
	        	String exception = (String) request.getAttribute("shiroLoginFailure");
	            model.addAttribute("msg",exception);
	        	return "redirect:/loginPage";
	        }
	    }
	    
	    //被踢出后跳转的页面
	    @RequestMapping(value = "/kickout", method = RequestMethod.GET)
	    public String kickOut() {
	        return "kickout";
	    }
	    
		@GetMapping("/sendMsg/{phone}")
		@ResponseBody
		public CustomResult<User> sendMsg(@PathVariable String phone) {
			//return userService.sendMsg(phone);
			return new CustomResult<>().failure(false, "0001", "短信次数已用完,请充值!");
		}	    
	    
		@GetMapping("/toResetPassword")
		public ModelAndView toResetPasswordPage(@RequestParam("sid")String sid,@RequestParam("username") String username) {
			String digitalSignature=sid.replace(" ","+");
			ModelAndView mv=new ModelAndView();
			if (!stringRedisTemplate.hasKey(digitalSignature)){
				mv.addObject("msg", "连接已失效！请重新找回密码！");
				mv.setViewName("/loginPage");
			}else {
				mv.setViewName("redirect:/resetPage?username="+username);
			}
			return mv;
		}
		
		@RequestMapping("/resetPage")
		public String toResetPage(@RequestParam("username") String username,Model model) {
			logger.info("进入重置密码界面");
			model.addAttribute("username", username);
			return "resetPassPage.html";
		}
		
		@RequestMapping("/toIndex")
		public String toIndexPage() {
			return "index.html";
		}
	}